// Fluxions 3D Engine
// vector2.hpp
// Copyright (C) 2000-2011 Jonathan Metzgar
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#ifndef FLUXIONS_VECTOR2_HPP
#define FLUXIONS_VECTOR2_HPP

#include "fluxions/math.hpp"

namespace Fluxions
{
	template <typename X>
	class TVector2
	{
	public:
		union
		{
			struct
			{
				X x, y;
			};
			struct
			{
				X s, t;
			};
			struct
			{
				X v[2];
			};
		};

		TVector2();
		TVector2(X _x, X _y);
		TVector2(const TVector2<X> & V);
		TVector2(const X V[2]);

		template <typename T> const TVector2<X> & operator = (const TVector2<T> & V);

		template <typename T> operator TVector2<T> () const;

		template <typename T> const TVector2<X> & operator *= (const T val);
		template <typename T> const TVector2<X> & operator /= (const T val);
		template <typename T> const TVector2<X> & operator += (const TVector2<T> & V);
		template <typename T> const TVector2<X> & operator -= (const TVector2<T> & V);

		template <typename T> TVector2<X> operator * (const T val) const;
		template <typename T> TVector2<X> operator / (const T val) const;
		template <typename T> TVector2<X> operator + (const TVector2<T> & V) const;
		template <typename T> TVector2<X> operator - (const TVector2<T> & V) const;

		template <typename T> const X operator * (const TVector2<T> & V) const;

		const X Length() const;
		const X LengthSquared() const;
		void Normalize();
	};
	
	//////////////////////////////////////////////////////////////////
	// I M P L E M E N T A T I O N ///////////////////////////////////
	//////////////////////////////////////////////////////////////////

	template<typename X>
	TVector2<X>::TVector2()
	{
	}

	template <typename X>
	TVector2<X>::TVector2(X x, X y)
		: x(x), y(y)
	{
	}

	template <typename X>
	TVector2<X>::TVector2(const X V[2])
		: x(V[0]), y(V[1])
	{
	}

	template <typename X>
	TVector2<X>::TVector2(const TVector2<X> & V)
		: x(V.x), y(V.y)
	{
	}

	template <typename X>
	template <typename T> 
	const TVector2<X> & TVector2<X>::operator = (const TVector2<T> & V)
	{
		x = V.x;
		y = V.y;
		return *this;
	}

	template <typename X>
	template <typename T> 
	TVector2<X>::operator TVector2<T> () const
	{
		return TVector2<T>(x, y);
	}

	template <typename X>
	template <typename T> 
	const TVector2<X> & TVector2<X>::operator *= (const T val)
	{
		x *= val;
		y *= val;
		return *this;
	}

	template <typename X>
	template <typename T> 
	const TVector2<X> & TVector2<X>::operator /= (const T val)
	{
		x /= val;
		y /= val;
		return *this;
	}

	template <typename X>
	template <typename T> 
	const TVector2<X> & TVector2<X>::operator += (const TVector2<T> & V)
	{
		x += V.x;
		y += V.y;
		return *this;
	}

	template <typename X>
	template <typename T> 
	const TVector2<X> & TVector2<X>::operator -= (const TVector2<T> & V)
	{
		x -= V.x;
		y -= V.y;
		return *this;
	}

	template <typename X>
	template <typename T> 
	TVector2<X> TVector2<X>::operator * (const T val) const
	{
		return TVector2<X>(x * val, y * val);
	}

	template <typename X>
	template <typename T> 
	TVector2<X> TVector2<X>::operator / (const T val) const
	{
		return TVector2<X>(x / val, y / val);
	}

	template <typename X>
	template <typename T> 
	TVector2<X> TVector2<X>::operator + (const TVector2<T> & V) const
	{
		return TVector2<X>(x + V.x, y + V.y);
	}

	template <typename X>
	template <typename T> 
	TVector2<X> TVector2<X>::operator - (const TVector2<T> & V) const
	{
		return TVector2<X>(x - V.x, y - V.y);
	}

	template <typename X>
	template <typename T> 
	const X TVector2<X>::operator * (const TVector2<T> & V) const
	{
		return x * V.x + y * V.y;
	}

	template <typename X>
	const X TVector2<X>::Length() const
	{
		return sqrt(x * x + y * y);
	}

	template <typename X>
	const X TVector2<X>::LengthSquared() const
	{
		return x * x + y * y;
	}

	template <typename X>
	void TVector2<X>::Normalize()
	{
		*this /= Length();
	}

	template <typename T>
	T DotProduct(const TVector2<T> & v1, const TVector2<T> & v2)
	{
		T out;
		out = v1.x * v2.x + v1.y * v2.y;
		return out;
	}

	typedef TVector2<float> Vector2f;
	typedef TVector2<double> Vector2d;
}

#endif
